package me.youline.dataServer.service.support.file;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import me.youline.dataServer.ConfigConstants;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.EncoderException;
import org.apache.commons.codec.net.URLCodec;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;

/**
 * 文件构造器
 * 
 * @author linhan
 *
 */
public class FileBuilder {

	/**
	 * 设定根目录
	 */
	private String root = "";

	/**
	 * 路径片段
	 */
	private List<String> pathFragments = new ArrayList<String>();

	/**
	 * 文件名
	 */
	private String fileName = "";

	/**
	 * 文件大小
	 */
	private long fileSize;

	/**
	 * 文件输入流
	 */
	private InputStream inputStream;

	private FileBuilder() {

	}

	/**
	 * 创建默认
	 * 
	 * @return
	 */
	public static FileBuilder newInstance() {
		return new FileBuilder();
	}

	public static FileBuilder newInstance(InputStream stream) {
		FileBuilder d = new FileBuilder();
		d.inputStream = stream;
		return d;
	}

	/**
	 * 设置根目录
	 * 
	 * @param root
	 * @return
	 */
	public FileBuilder root(String root) {
		this.root = root;
		return this;
	}

	/**
	 * 添加目录
	 * 
	 * @param dirName
	 * @return
	 */
	public FileBuilder dir(String dirName) {
		pathFragments.add(dirName);
		return this;
	}

	/**
	 * 设置源输入流
	 * 
	 * @param stream
	 * @return
	 */
	public FileBuilder src(InputStream stream) {
		this.inputStream = stream;
		return this;
	}

	/**
	 * 设置文件
	 * 
	 * @param fileName
	 * @return
	 */
	public FileBuilder file(String fileName) {
		this.fileName = fileName;
		return this;
	}

	/**
	 * 设置文件大小
	 * 
	 * @param size
	 * @return
	 */
	public FileBuilder fileSize(long size) {
		this.fileSize = size;
		return this;
	}

	/**
	 * 获取文件实体
	 * 
	 * @return
	 */
	public FileEntity getEntity() {
		return new FileEntity(this);
	}

	/**
	 * 获取文件实体
	 * 
	 * @author linhan
	 *
	 */
	public static class FileEntity {

		private FileEntity() {
		}

		private static URLCodec codec = new URLCodec();;
		private String filePath;

		private String dirPath;

		private FileBuilder fileBuilder;

		private FileEntity(FileBuilder builder) {
			this.fileBuilder = builder;
		}

		/**
		 * 创建目录
		 */
		private void createDir() {
			StringBuilder builder = new StringBuilder();
			builder.append(fileBuilder.root);
			for (String dirName : fileBuilder.pathFragments) {
				builder.append(ConfigConstants.PATH_SEPARATOR).append(dirName);
				File dir = new File(builder.toString());
				if (!dir.exists()) {
					dir.mkdir();
				}
			}
			builder.append(ConfigConstants.PATH_SEPARATOR);
			this.dirPath = builder.toString();
		}

		/**
		 * 获取去除根目录的文件路径
		 * 
		 * @return
		 */
		public String getFilePathExcludeRoot() {
			if (StringUtils.isBlank(fileBuilder.root)) {
				return this.getFilePath();
			}
			return this.getFilePath().substring(fileBuilder.root.length());
		}

		/**
		 * 去除根目录的目录路径
		 *
		 * @return
		 */
		public String getDirPathExcludeRoot() {
			if (StringUtils.isBlank(fileBuilder.root)) {
				return this.getDirPath();
			}
			String dirPath = this.getDirPath();
			return dirPath.substring(fileBuilder.root.length());
		}

		/**
		 * 获取目录路径
		 * 
		 * @return
		 */
		public String getDirPath() {
			if (StringUtils.isNoneBlank(this.dirPath)) {
				return dirPath;
			}
			StringBuilder builder = new StringBuilder();
			builder.append(fileBuilder.root);
			for (String dirName : fileBuilder.pathFragments) {
				builder.append(ConfigConstants.PATH_SEPARATOR).append(dirName);
			}
			builder.append(ConfigConstants.PATH_SEPARATOR);
			this.dirPath = builder.toString();
			return this.dirPath;
		}

		/**
		 * 获取完整文件路径
		 * 
		 * @return
		 */
		public String getFilePath() {
			if (StringUtils.isNoneBlank(filePath)) {
				return filePath;
			} else {
				filePath = this.getDirPath() + fileBuilder.fileName;
				return filePath;
			}
		}

		/**
		 * 获取文件尺寸大小byte
		 * 
		 * @return
		 */
		public long getFileSize() {
			return fileBuilder.fileSize;
		}


		public File getFile() {
			return new File(this.getFilePath());
		}

		/**
		 * 将输入流存储至指定目录文件
		 * 
		 * @throws IOException
		 */
		public void save() throws IOException {
			if (fileBuilder.inputStream == null) {
				throw new RuntimeException("无初始化输入流，无法进行保存");
			}
			FileOutputStream out = null;
			createDir();
			try {
				out = new FileOutputStream(new File(this.getFilePath()));
				IOUtils.copy(fileBuilder.inputStream, out);
			} catch (IOException e) {
				throw e;
			} finally {
				if (out != null) {
					try {
						out.close();
					} catch (IOException e) {
						
					}
				}
				if (fileBuilder.inputStream != null) {
					try {
						fileBuilder.inputStream.close();
					} catch (IOException e) {

					}
				}
			}
		}

		/**
		 * 将指定输入流存储至指定目录文件
		 * 
		 * @param input
		 * @throws IOException
		 */
		public void save(InputStream input) throws IOException {
			FileOutputStream out = null;
			try {
				createDir();
				out = new FileOutputStream(new File(this.getFilePath()));
				IOUtils.copy(input, out);
			} catch (IOException e) {
				throw e;
			} finally {
				if (out != null) {
					try {
						out.close();
					} catch (IOException e) {

					}
				}
			}
		}

		/**
		 * 清楚资源
		 */
		public void consumeEntity() {
			if (fileBuilder.inputStream != null) {
				try {
					fileBuilder.inputStream.close();
				} catch (IOException e) {

				}
			}
		}

		public static String encodePath(String unEncodedPath) {
			try {
				return codec.encode(unEncodedPath);
			} catch (EncoderException e) {
				throw new RuntimeException(e);
			}
		}

		public static String decodePath(String encodedPath) {
			try {
				return codec.decode(encodedPath);
			} catch (DecoderException e) {
				throw new RuntimeException(e);
			}
		}
	}

}
